import type { Directive } from 'vue'

interface LazyLoadElement extends HTMLImageElement {
  _observer?: IntersectionObserver
}

import defaultImage from '@/asset/images/none.png'

/**
 * mounted钩子 - 指令绑定到元素时调用
 * @param el - 指令绑定的元素，类型为LazyLoadElement
 * @param binding - 指令绑定对象，包含指令相关的信息
 */

// 定义懒加载指令
export const lazyLoad: Directive = {
  // mounted钩子 - 指令绑定到元素时调用
  mounted(el: LazyLoadElement, binding) {
    // 缓存原始图片地址到dataset,缓存真实图片地址
    el.dataset.src = binding.value

    // 创建IntersectionObserver观察器实例
    const observer = new IntersectionObserver(
      // 观察器回调函数，当观察的元素进入/离开视口时触发
      (entries) => {
        entries.forEach((entry) => {
          // 判断元素是否进入视口
          if (entry.isIntersecting) {
            // 创建临时图片对象用于预加载真实图片
            const tempImg = new Image()

            // 图片加载成功回调
            tempImg.onload = () => {
              el.src = binding.value // 设置真实图片地址
              observer.unobserve(el) // 停止观察
            }
            // 图片加载失败回调
            tempImg.onerror = () => {
              el.src = defaultImage // 加载失败时使用默认图片
              console.error('图片加载失败:', binding.value)
            }
            // 开始加载真实图片（触发加载过程）
            tempImg.src = binding.value
          }
        })
      },
      {
        // 观察器配置选项：
        rootMargin: '0px 0px 300px 0px', // 预加载300px外图片
        threshold: 0.01, // 元素可见比例达到1%时触发回调
      },
    )

    // 开始观察目标元素
    observer.observe(el)
    // 存储观察器实例以便卸载时清理
    el._observer = observer
  },
  // unmounted钩子 - 指令从元素上卸载时调用
  unmounted(el: LazyLoadElement) {
    // 清理观察器，避免内存泄漏
    if (el._observer) {
      el._observer.unobserve(el)
    }
  },
}
